﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using System.Reflection;
using FinPlusCommon;
using log = Logger.Logger;
using u = FinPlusUtility.Utility;

namespace FinPlusWPFControls
{
    public class FinPlusGridColHelper : FinPlusControl
    {
        public ColMaps ColMaps { get; private set; }

        private enum Params { Id, QuoteInstrument, LinkedId }
        private FinPlusGroupGrid _grid;
        private string _configPath;
       
        //constuct
        public FinPlusGridColHelper(IDictionary<string, string[]> colFormats = null, IDictionary<string, string[]> colTypes = null, string[] enabledCols = null, IDictionary<string, string[]> colLinks = null)
        {
            ColMaps = new ColMaps(colTypes, enabledCols, colLinks, colFormats);
            _configPath = u.GetAssemblyPath(Assembly.GetEntryAssembly());
            IsValid = true;
        }

        //public
        public void Link(FinPlusGroupGrid grid, RoutedEventHandler filterbarAdd,  RoutedEventHandler filterbarRemove)
        {
            try
            {
                _grid = grid;
                ColMaps.Load(grid, ContainerId, filterbarAdd, filterbarRemove);
            }
            catch(Exception e)
            {
                IsValid = log.Log(Logger.Level.Warning, Id, Config, e.Message, e);
            }
        }

        public DataGridTemplateColumn GetTemplate(string name, string type)
        {
            if (ColMaps.HasCol(name)) 
                return null; //already added

            var colMap = ColMaps.GetMap(name, type);
            LinkEvents(colMap, name);//links events re popups
            ColMaps.ListColNames.Add(name);

            var col = colMap.GetTemplate(TagProperty, name);
            return col;
        }

        public void SetColState(DataGrid dataGrid, FinPlusColSelectBar colSelectBar, string states)
        {
            var stateArray = u.StringToListOfArrays(states, ',', "{}", null);
            
            foreach (var state in stateArray)
            {
                try
                {
                    var f = dataGrid.Columns.Where(c => c.GetValue(TagProperty).ToString() == state[0]);
                    if(f.Count() < 1) 
                        continue;
                    
                    var col = f.First();
                    col.DisplayIndex = int.Parse(state[1]);
                    
                    var width = double.NaN;
                    double.TryParse(state[2], out width);
                    col.Width = width; 
                    col.Visibility = u.EnumParse<Visibility>(state[3], Visibility.Visible);
                    
                    if (colSelectBar != null) 
                        colSelectBar.AddButton(state[0], col.Visibility == Visibility.Collapsed);
                }
                catch (Exception e)
                {
                    log.Log(Logger.Level.Warning, Id, Config, e.Message, e);
                }
            }
        }

        public string GetColState(DataGrid dataGrid)
        {
            try
            {
                var s = dataGrid.Columns.OrderBy(x => x.DisplayIndex).Select(x => string.Format("{0},{1},{2},{3}", x.GetValue(TagProperty), x.DisplayIndex, x.Width, x.Visibility));
                return string.Format("{{{{{0}}}}}", String.Join("},{", s.ToArray()));
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, Id, Config, e.Message, e);
                return null;
            }
        }

        //private
        private void LinkEvents(ColMap colMap, string name)
        {
            //TODO rewrite
            if (colMap.ColType.EndsWith(".FuncEditPopup") && colMap.IsEnabled)
            {
                if (ColMaps.FuncEditorPopupCols == null)
                {
                    ColMaps.FuncEditorPopupCols = new Dictionary<string, string>();
                    _grid.DynFuncs.FunctionChanged += DataGridBookedTrade_Update;
                }
                ColMaps.FuncEditorPopupCols[name] = colMap.Links;
            }
            else if (colMap.ColType.EndsWith(".QuotePopup") && colMap.IsEnabled)
            {
                if (ColMaps.QuotePopupCols == null)
                {
                    ColMaps.QuotePopupCols = new Dictionary<string, string>();
                    _grid.DynFuncs.FunctionChanged += DataGridColQuote_Update;
                }
                ColMaps.QuotePopupCols[name] = colMap.Links;
            }
        }

        private async void FuncEditorPopUp(IFinPlusFuncDynamic funcDynamic, string propertyName)
        {
            try
            {
                //TODO move to col
                await Task.Run(() =>
                {
                    object trade, id;
                    if (!funcDynamic.TryGetObject(Params.Id.ToString(), out id))
                        return;

                    if (!GetPermission(Params.QuoteInstrument.ToString(), Params.Id.ToString(), id.ToString()).CanWrite)
                        return;

                    if (funcDynamic.TryGetObject(propertyName, out trade))
                        FinPlusWindow.OpenEditor(Function.FromString(trade.ToString()), "FuncEdit", Env);
                });
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Warning, Id, Config, e.Message, e);
            }
        }

        private async void QuotePopUp(IFinPlusFuncDynamic funcDynamic, string propertyName)
        {
            try
            {
                //TODO move to col
                await Task.Run(() => 
                {
                    object quoteRequest, id;
                    if (!funcDynamic.TryGetObject(propertyName, out quoteRequest))
                        return;

                    if (!funcDynamic.TryGetObject(Params.Id.ToString(), out id))
                        return;

                    var quote = Function.FromString(quoteRequest.ToString());
                    var linkedId = quote[Params.LinkedId.ToString()].ToString();

                    if ((!string.IsNullOrEmpty(linkedId) && !linkedId.Equals(ContainerId)))
                        return;

                    if (GetPermission(Params.QuoteInstrument.ToString(), Params.Id.ToString(), quote.Get(Params.Id.ToString()).Value).CanWrite)
                        FinPlusValueQuotePopup.Show(quote, funcDynamic, id.ToString(), ColMaps.QuotePopupCols[propertyName], ContainerId);
               });
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Warning, Id, Config, e.Message, e);
            }
        }

        //events
        private void DataGridColQuote_Update(object s, PropertyChangedEventArgs a) 
        { 
            if (ColMaps.QuotePopupCols.ContainsKey(a.PropertyName)) 
                QuotePopUp((IFinPlusFuncDynamic)s, a.PropertyName);
        }      
        private void DataGridBookedTrade_Update(object s, PropertyChangedEventArgs a)
        {
            if (ColMaps.FuncEditorPopupCols.ContainsKey(a.PropertyName))  
                FuncEditorPopUp((IFinPlusFuncDynamic)s, a.PropertyName); 
        }
    }

    public class ColMaps: Dictionary<string, ColMap>
    {
        public Dictionary<string, string> QuotePopupCols { get; set; }
        public Dictionary<string, string> FuncEditorPopupCols { get; set; }
        public IList<string> ListColNames { get; set; }
        public string LinkedId { get; private set; }

        private enum Params { StringFormat, Type, InputMask }
        private IDictionary<string, string[]> _colTypes, _colFormats, _colLinks;
        private RoutedEventHandler _filterbarAdd, _filterbarRemove;
        private FinPlusGroupGrid _grid;
        private string[] _enabledCols;

        //constructor
        public ColMaps(IDictionary<string, string[]> colTypes, string[] enabledCols, IDictionary<string, string[]> colLinks, IDictionary<string, string[]> colFormats)
        {
            _colTypes = colTypes;
            _enabledCols= enabledCols;
            _colFormats= colFormats;
            _colLinks= colLinks;
            ListColNames = new List<string>();
        }

        //public
        public ColMap GetMap(string colName, string type)
        {
            ColMap colMap;

            if (this.ContainsKey(colName))
                return this[colName];

            return colMap = new ColMap(colName, LinkedId, _filterbarAdd, _filterbarRemove);
        }

        public void Load(FinPlusGroupGrid grid, string linkedId, RoutedEventHandler filterbarAdd, RoutedEventHandler filterbarRemove)
        {
            _grid = grid;
            LinkedId = linkedId;
            _filterbarAdd = filterbarAdd;
            _filterbarRemove = filterbarRemove;
            ColTypes();
            ColEnable();
            ColLinks();
            ColFormats();
        }

        public bool HasCol(string name)
        {
            if (ListColNames.Contains(name))
                return true;

            if (QuotePopupCols != null && (QuotePopupCols.ContainsValue(name) || QuotePopupCols.ContainsKey(name)))
                return true;

            if (FuncEditorPopupCols != null && (FuncEditorPopupCols.ContainsValue(name) ||
                FuncEditorPopupCols.ContainsKey(name)))
                return true;

            return false;
        }

        //private
        private void ColTypes()
        {
            try
            {
                if (_colTypes == null) return;

                foreach (var colType in _colTypes)
                    foreach (var colName in colType.Value)
                        this[colName] = new ColMap(colName, LinkedId, _filterbarAdd, _filterbarRemove, colType.Key);
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, "NA", "NA", e.Message, e);
            }
        }

        private void ColEnable()
        {
            try
            {
                if (_enabledCols == null) return;

                foreach (var colName in _enabledCols)
                {
                    if (!this.ContainsKey(colName))
                        this[colName] = new ColMap(colName, LinkedId, _filterbarAdd, _filterbarRemove);
                    this[colName].IsEnabled = true;
                }
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, "NA", "NA", e.Message, e);
            }
        }

        private void ColLinks()
        {
            try
            {
                if (_colLinks == null) return;

                foreach (var colLink in _colLinks)
                {
                    foreach (var colName in colLink.Value)
                    {
                        if (!this.ContainsKey(colName))
                            this[colName] = new ColMap(colName, LinkedId, _filterbarAdd, _filterbarRemove);
                        var colMap = this[colName];
                        colMap.Links = colMap.Value = colLink.Key;
                    }
                }
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, "NA", "NA", e.Message, e);
            }
        }

        private void ColFormats()
        {
            try
            {
                if (_colFormats == null) return;

                foreach (var colFormat in _colFormats)
                {
                    foreach (var colName in colFormat.Value)
                    {
                        if (!this.ContainsKey(colName))
                            this[colName] = new ColMap(colName, LinkedId, _filterbarAdd, _filterbarRemove);
                        var colMap = this[colName];
                        var format = (Hashtable)_grid.FindResource(colFormat.Key);
                        colMap.StringFormat = format[Params.StringFormat.ToString()].ToString();
                        colMap.Type = format[Params.Type.ToString()].ToString();
                        colMap.InputMask = format[Params.InputMask.ToString()].ToString();
                    }
                }
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, "NA", "NA", e.Message, e);
            }
        }
    }

    public class ColMap
    {
        public string Name { get; private set; }
        public string LinkedId { get; private set; }
        public CheckBox FilterCheck {get; private set;}
        public string ColType {get; set;}
        public string Links {get; set;}
        public string StringFormat {get; set;}
        public string InputMask {get; set;}
        public string Type {get; set;}
        public string Value { get; set; }
        public bool IsEnabled {get; set;}

        private const double _defaultColWidth = 70;

        //construct
        public ColMap(string name, string linkedId, RoutedEventHandler filterbarAdd, RoutedEventHandler filterbarRemove, string colType = "ValueFormat", string type = "String")
        {
            Name = name;
            LinkedId = linkedId;
            ColType = colType;
            Links = string.Empty;
            StringFormat = string.Empty;
            InputMask = string.Empty;
            Type = type;
            Value = string.Empty;
            FilterCheck = new CheckBox() { Content = name, Tag = name, FlowDirection = FlowDirection.RightToLeft };
            FilterCheck.Checked += filterbarAdd;
            FilterCheck.Unchecked += filterbarRemove;
        }

        //public
        public DataGridTemplateColumn GetTemplate(DependencyProperty tag, string name)
        {
            var res = FinPlusDInject.Get.RegType(LinkedId, ColType, ToArray());
            DataGridTemplateColumn col = null;
            
            if (res == null)
                col = new FinPlusGridColFormat(Name, string.Empty, string.Empty, Type, FilterCheck, Type.Equals("String"), false);
            else
                col = (DataGridTemplateColumn)res;

            col.SetValue(tag, name);
            col.Width = _defaultColWidth;

            if (col.GetType().Equals(typeof(FinPlusGridColExclude)))
                return null; //exclude type

            return col;
        }

        //private
        private object[,] ToArray()
        {
            return new object[,] { { "name", Name },{ "linkedId", LinkedId },{ "colType", ColType },  { "links", Links }, { "stringFormat", StringFormat }, { "inputMask", InputMask }, { "type", Type }, { "isEnabled", IsEnabled }, {"filterCheck", FilterCheck}};
        }
    }
}
